from web3 import Web3
from contracts.node_registry import CONTRACT_ADDRESS, ABI
from datetime import datetime, timedelta
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.interval import IntervalTrigger
from flask import Flask
from .models import DetectionNode
from . import db

class Detector:
    def __init__(self, web3: Web3, app: Flask):
        self.web3 = web3
        self.app = app
        self.contract = self.web3.eth.contract(address=CONTRACT_ADDRESS, abi=ABI) if web3.is_connected() else None
        self.address = self.web3.eth.accounts[0] if web3.is_connected() else "0x0"
        self.heartbeat_interval = 2  # 心跳信号间隔秒数
        self.check_interval = 5  # 状态检查间隔秒数
        self.nodes = {}  # 节点和最后状态更新时间的映射
        self.scheduler = BackgroundScheduler()  # 初始化调度器
        self.task_started = False  # 标记任务是否已启动

        # 启动调度器
        self.scheduler.start()

    # 设置 web3
    def set_web3(self, web3: Web3):
        self.web3 = web3
        self.contract = self.web3.eth.contract(address=CONTRACT_ADDRESS, abi=ABI) if web3.is_connected() else None
        self.address = self.web3.eth.accounts[0] if web3.is_connected() else "0x0"

    # 初始化节点列表
    def init_nodes(self):
        with self.app.app_context():
            node_list = self.get_node_status()
            for node in node_list:
                self.nodes[node.node_address] = node.last_updated

    # 获得全部节点状态
    def get_node_status(self):
        with self.app.app_context():
            return DetectionNode.query.all()
        # return self.contract.functions.getAllNodes().call()

    # 更新节点的状态
    def update_node_status_on_chain(self, node_address, is_active: int):
        with self.app.app_context():
            node = DetectionNode.query.get(node_address)
            if node:
                node.is_active = is_active
                node.last_updated = self.nodes[node_address]
                db.session.commit()
                print(f"Node {node_address} status updated to {'active' if is_active == 1 else 'inactive'} on chain")

    # 检查节点的状态
    def check_node_status(self):
        with self.app.app_context():
            now = datetime.utcnow()
            for node_address, last_heartbeat in self.nodes.items():
                # print(f"now is {now}, last heartbeat is {last_heartbeat}")
                # print(f"{now-last_heartbeat}:{timedelta(seconds=self.heartbeat_interval)}")
                if now - last_heartbeat > timedelta(seconds=self.heartbeat_interval):
                    # 认为节点故障
                    self.update_node_status_on_chain(node_address, 0)
                else:
                    # 认为节点正常
                    self.update_node_status_on_chain(node_address, 1)

    def check_node_exists(self, node_address):
        with self.app.app_context():
            return DetectionNode.query.get(node_address) is not None

    # 启动任务
    def start_check(self):
        if not self.task_started:
            self.scheduler.add_job(self._check_node_status_with_context, trigger=IntervalTrigger(seconds=self.check_interval))
            self.task_started = True

    # 停止任务
    def stop_check(self):
        if self.task_started:
            self.scheduler.remove_all_jobs()
            self.task_started = False

    # 包装 check_node_status 方法，使其在应用上下文中运行
    def _check_node_status_with_context(self):
        with self.app.app_context():
            self.check_node_status()
